import { ConnectStatus } from "@/constants/constants";
import { SocketOption } from "./SocketOption";
import { controller } from "@/engine/Controller";
import { SimulateStatusType } from "@/engine/_";
import { ElNotification } from "element-plus";
import local from "@/util/local";

export class SocketService {
  ws?: WebSocket = undefined;
  heartBeatTimer?: NodeJS.Timeout = undefined;
  serverResponseTimer?: NodeJS.Timeout = undefined;
  reconnectTimer?: NodeJS.Timeout = undefined;
  heartBeatDelay: number;
  serverResponseDelay: number;
  reconnectDelay: number;
  reconnectTime = 0;
  status: ConnectStatus = ConnectStatus.UNCONNECT;
  autostartOnce = false;
  uri: string;
  userId?:string
  isHeartBeatMessage: (msg: { type: string }) => boolean;
  createHeartBeatMessage: (() => string) | undefined;
  onSendHeartBeat?: (service: SocketService) => void;
  msgHandler: { [p: string]: (res: any) => void };
  maxReconnectTime=100
  constructor(option: SocketOption) {
    const {
      uri,
      heartBeatDelay,
      serverResponseDelay,
      reconnectDelay,
      msgHandler,
      isHeartBeatMessage,
      createHeartBeatMessage,
      onSendHeartBeat,
      maxReconnectTime
    } = option;
    this.uri = uri;
    this.heartBeatDelay = heartBeatDelay;
    this.serverResponseDelay = serverResponseDelay;
    this.reconnectDelay = reconnectDelay;
    this.msgHandler = msgHandler;
    this.isHeartBeatMessage = isHeartBeatMessage;
    this.createHeartBeatMessage = createHeartBeatMessage;
    this.onSendHeartBeat = onSendHeartBeat;
    this.maxReconnectTime = maxReconnectTime;
  }
  start() {
    if (this.ws && this.status == ConnectStatus.CONNECTED) return;
    this.ws = new WebSocket(this.uri);
    this.ws.onopen = this.onOpen.bind(this);
    this.ws.onmessage = this.onMessage.bind(this);
    this.ws.onclose = this.onClose.bind(this);
    this.ws.onerror = this.onError.bind(this);
  }

  close() {
    this.status = ConnectStatus.CLOSED;
    this.clearAllTimer();
    this.ws?.close();
    this.reconnect();
  }

  onOpen() {
    this.status = ConnectStatus.CONNECTED;
    this.reconnectTime = 0;
    this.clearAllTimer();
  }

  onMessage(e: MessageEvent) {
    if (this.serverResponseTimer) clearTimeout(this.serverResponseTimer);
    const res = JSON.parse(e.data);
    if (res.type === "tcp_opaque_action_error") {
      ElNotification({
        title: local.localeTrans("tips"),
        message: res.message,
        position: 'bottom-right',
        type: "error"
      });
    }
    this.msgHandler.infoSocketMessage(res);
    if (this.msgHandler[res.type] && controller.toolbarService.status !== SimulateStatusType.finish) {
      this.msgHandler[res.type](res);
    } else {
      if (!this.msgHandler[res.type]) {
        console.error("unknown socket type:" + res.type);
      }
    }
  }

  onClose() {
    this.status = ConnectStatus.CLOSED;
    console.log("socket close");
    this.reconnect();
  }

  onError(e: Event) {
    console.log("socket error", e);
    this.reconnect();
  }

  send(str: string) {
    console.log(this.ws, str, 'this.wsthis.ws');
    this.ws?.send(str);
  }

  sendJSON(obj: any) {
    this.ws?.send(JSON.stringify(obj));
  }

  reconnect() {
    if (this.status === ConnectStatus.RECONNECTING) return;
    if (this.reconnectTimer) return;
    this.status = ConnectStatus.RECONNECTING;
    this.reconnectTimer = setInterval(() => {
      if (this.reconnectTime >= this.maxReconnectTime) {
        if (this.reconnectTimer) clearInterval(this.reconnectTimer);
        console.error("重连失败");
        this.status = ConnectStatus.CLOSED;
        return;
      }
      this.reconnectTime++;
      console.error("socket 连接断开，正在尝试重连...：" + this.reconnectTime);
      this.start();
    }, this.reconnectDelay);
  }

  clearAllTimer() {
    if (this.heartBeatTimer) clearInterval(this.heartBeatTimer);
    if (this.reconnectTimer) clearInterval(this.reconnectTimer);
    if (this.serverResponseTimer) clearTimeout(this.serverResponseTimer);
    this.heartBeatTimer = undefined;
    this.serverResponseTimer = undefined;
    this.reconnectTimer = undefined;
  }
}
